//
//  PMShape.m
//  PezMonkey
//
//  Created by Spence DiNicolantonio on 10/29/09.
//  Copyright 2009 Necrosoft. All rights reserved.
//

/**
 * A collision shape. PMShape objects are used within a PMSpace to detect and 
 * control collisions of rigid bodies. PMShape objects are tied to a PMBody object
 * that it is meant to represent. The physical result of any interaction with other
 * PMShapes in a given PMSpace will in turn be applied to the PMShape's referenced
 * PMBody object. PMShape objects maintain surface velocity, friction, and elasticity  
 * properties that influence the affect on and by other PMShapes in a PMSpace. 
 * 
 * This class should never be instantiated directly, rather, PMShapes should be 
 * instantiated using the PMCircleShape, PMSegmentShape, and PMPolygonShape subclasses. 
 * 
 * In terms of processing, PMCircleShapes are the most efficient, and PMPolygonShapes
 * are the least efficient. Note that at this time, PMSegmentShapes cannot collide 
 * with other PMSegmentShapes. They are intended for use as a static shape.
 * 
 * When creating a PMShape object for static use, the static body singleton should 
 * be used. This can be attained using the static staticBody method of the PMBody
 * class.
 */
#pragma mark TODO: Add static shapes to description

#import "PMShape.h"
#import "PMBody.h"


@implementation PMShape

@synthesize body;
@synthesize data;


#pragma mark -
#pragma mark Dealloc

/**
 * Releases member objects and frees memory used for cpShape before deallocating.
 */
- (void)dealloc {
	[self.data release];
	[self.body release];
	cpShapeFree(shape);
	[super dealloc];
}


#pragma mark -
#pragma mark Getters

/**
 * Returns the receiver's cpShape reference. This is not intended for external use.
 */
- (cpShape *)cpShape {
	return shape;
}

/**
 * Returns the receiver's shape type.
 */
- (PMShapeType)type {
	return (PMShapeType) shape->klass->type;
}

/**
 * Returns the receiver's bounding box.
 */
- (PMBoundingBox)boundingBox {
	cpShapeCacheBB(shape);
	return shape->bb;
}

/**
 * Returns the receiver's elasticity.
 */
- (PMFloat)elasticity {
	return shape->e;
}

/**
 * Returns the receiver's coefficient of friction.
 */
- (PMFloat)friction {
	return shape->u;
}

/**
 * Returns the receiver's surface velocity vector.
 */
- (PMVect)surfaceVelocity {
	return (PMVect) shape->surface_v;
}

/**
 * Returns the receiver's collsion Type. This value can be used to sort out custom 
 * collision functionality.
 */
- (NSUInteger)collisionType {
	return shape->collision_type;
}

/**
 * Returns the receiver's collision group. Shapes in the same non-zero group do 
 * not generate collisions. This can be useful when creating an object out of 
 * multiple PMShapes that you don't want to self collide.
 */
- (NSUInteger)collisionGroup {
	return shape->group;
}

/**
 * Returns the receiver's collision layer mask. This bit-mask denotes all of
 * layers on which the PMShape can collide. PMShapes only collide with other 
 * PMShapes sharing a common collision layer. By default, PMShapes occupy all 32 
 * layers.
 */
- (PMLayerMask)layers {
	return shape->layers;
}

/**
 * Returns the receiver's unique shape ID. 
 */
- (NSUInteger)shapeID {
	return shape->id;
}


#pragma mark -
#pragma mark Setters

/**
 * Sets the receiver's elasticity to a given value.
 */
- (void)setElasticity:(PMFloat)elasticity {
	shape->e = elasticity;
}

/**
 * Sets the receiver's coefficient of friction to a given value.
 */
- (void)setFriction:(PMFloat)friction {
	shape->u = friction;
}

/**
 * Sets the receiver's surface velocity to a given vector.
 */
- (void)setSurfaceVelocity:(PMVect)surfaceVelocity {
	shape->surface_v = surfaceVelocity;
}

/**
 * Sets the receiver's collision type to a given value.
 */
- (void)setCollisionType:(NSUInteger)collisionType {
	shape->collision_type = collisionType;
}

/**
 * Sets the receiver's collision group to a given value.
 */
- (void)setCollisionGroup:(NSUInteger)collisionGroup {
	shape->group = collisionGroup;
}

/**
 * Sets the receiver's collision Layer mask to the given PMLayerMask.
 */
- (void)setLayers:(PMLayerMask)layers {
	shape->layers = layers;
}


#pragma mark -
#pragma mark Other Methods

/**
 * Determines whether a given point lies within the receiver.
 */
- (BOOL)isPointInShape:(PMVect)point {
	return cpShapePointQuery(shape, point);
}

/**
 * Resets the internal counter used to set unique hash IDs for all created collision
 * shapes. This method should be called before populating a PMSpace with PMShape
 * objects.
 */
+ (void)resetShapeIDCounter {
	cpResetShapeIdCounter();
}

@end
